import { CurrUser, UserAction, UserDispatchContext, updateUser } from "@/providers/UserContextProvider"
import { Modal } from "antd"
import { isNil } from "ramda"
import { Dispatch, useContext, useRef } from "react"

type PageResult<T> = {
    success: boolean
    data: T[]
    total: number
}

type BizResult = {
    code: string
    data: any
    msg: string
    err_data?: any
}

interface CallApiParams {
    dispatch?: Dispatch<UserAction>;
    service: string;
    params?: any;
}

function _page_query(
    dispatch: Dispatch<UserAction>,
    service: string,
    pageNum: number,
    pageSize: number,
    params: any,
): Promise<PageResult<any>> {
    const q_params = {
        page_num: pageNum,
        page_size: pageSize,
        params,
    }

    return callApi({ dispatch, service, params: q_params })
        .then(_data => {
            const { items, total } = _data
            const _res: PageResult<any> = {
                data: items,
                success: true,
                total,
            }
            return _res
        })
        .catch(() => {
            return {
                data: [],
                success: true,
                total: 0,
            }
        })
}

function _login(userDispatch: React.Dispatch<UserAction>, username: string, password: string) {
    const resp = fetch("/login", {
        method: "POST",
        headers: {
            "Content-Type": "application/json;charset=UTF-8",
        },
        body: JSON.stringify({
            username,
            password,
        }),
    })
        .then(res => res.json())
        .then(({ msg, code, data }) => {
            if (code === "200") {
                updateUser(userDispatch, data)
                return data
            }
            throw {
                message: msg,
                name: code,
            }
        })
    return resp
}

function callApi({ dispatch = undefined, service, params = {} }: CallApiParams): Promise<any> {
    const biz_content = JSON.stringify(params)
    const form_data = `service=${service}&biz_content=${biz_content}`

    const token = localStorage.getItem("token")

    return fetch("/api/gateway", {
        method: "POST",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
            "X-Token": token ?? "",
        },
        body: form_data,
    })
        .then(res => res.json())
        .then(({ msg, code, data, err_data }) => {
            if (code === "200") {
                return data
            }
            throw {
                message: msg,
                name: code,
                err_data: err_data,
            }
        })
        .catch(err => {
            if (!isNil(dispatch)) {
                if (err.name === "TokenInvalid" || err.message === "缺少X-Token头") {
                    const newUser: CurrUser = {
                        username: "TokenInvalid",
                        token: "TokenInvalid",
                    }
                    dispatch({ type: "updateUser", payload: newUser })
                }
            }

            throw err
        })
}

type ApiClientFactory = (dispatch: Dispatch<UserAction>) => {
    pageQuery: (service: string, pageNum: number, pageSize: number, params: any) => Promise<PageResult<any>>
    login: (username: string, password: string) => Promise<any>
    apiRpc: (service: string, params: any) => Promise<any>
}

const createApiClient: ApiClientFactory = dispatch => {
    const pageQuery = async (
        service: string,
        pageNum: number,
        pageSize: number,
        params: any,
    ): Promise<PageResult<any>> => _page_query(dispatch, service, pageNum, pageSize, params)

    const login = async (username: string, password: string): Promise<any> => _login(dispatch, username, password)

    const call = async (service: string, params: any): Promise<any> => callApi({ dispatch, service, params })

    return {
        pageQuery,
        login,
        apiRpc: call,
    }
}

export { createApiClient, callApi }
export type { ApiClientFactory, CallApiParams }
